const { articleModel } = require("../models/article")
const { categoryModel } = require("../models/category")
const { userModel } = require("../models/user")
const { getuid, verifyToken } = require('../utils/auth')
const moment = require('moment')
moment.locale('zh-cn')

class ArticleController {
  static async createArticle(ctx) {
    // 参数校验
    ctx.verifyParams({
      title: { type: 'string', min: 1, max: 50, required: true },
      content: { type: 'string', allowEmpty: true, required: false },
      // not required
      desc: { type: 'string', max: 200, allowEmpty: true, required: false },
      publish: { type: 'boolean', required: false },
      tags: {
        type: 'array',
        itemType: 'object',
        rule: {
          _id: { type: 'string', min: 24, max: 24, required: true },
          name: { type: 'string', required: true }
        },
        required: false
      },
      category: {
        type: 'object',
        rule: {
          _id: { type: 'string', min: 24, max: 24, required: true },
          name: { type: 'string', required: true }
        },
        required: false
      }
    })
    // 获取参数
    const { title, desc, content, publish, tags, category } = ctx.request.body

    // console.log("publish:", publish)
    const uid = getuid(ctx)

    // 业务逻辑/数据库操作
    const newArticle = new articleModel({
      author_id: uid,
      title,
      desc,
      content,
      publish,
      tags,
      category,
      publishDate: publish ? Date.now() : null
    })

    await newArticle.save()

    // 返回请求结果
    ctx.succ({
      data: {
        newArticle: newArticle.toJSON()
      }
    })
  }

  static async getArticleById(ctx) {
    const id = ctx.request.params.id
    ctx.verifyParams({
      id: {
        type: 'string', min: 24, max: 24, trim: true
      }
    }, { id })

    // 身份验证（因为该接口允许不登录时使用）
    const auth = verifyToken(ctx.request.headers['authorization'])
    ctx.state.user = auth //为了使用getuid()
    const uid = getuid(ctx)

    let article = await articleModel.findOne({
      _id: id,
      publish: true
    })

    // 如果发布文章未找到，尝试查找未发布的文章（需用户登录）
    if (!article && uid) {
      article = await articleModel.findOne({
        _id: id,
        author_id: uid
      })
    }

    if (!article) {
      ctx.result({
        code: 404,
        message: "文章不存在，或已被删除"
      })
      return
    }

    // 阅读量+1
    if (uid != article.author_id) {
      article = await articleModel.findByIdAndUpdate(id, { $inc: { readCount: 1 } }, {
        new: true
      })
      // await articleModel.updateOne({ _id: id }, )
    }

    //保存历史记录
    if (uid != article.author_id && uid) {
      let user = await userModel.findById(uid)
      if (user.history.length >= 30) {
        user.history.shift()
      }
      user.history.push({
        article_id: article._id,
        readDate: Date.now()
      })
      await userModel.updateOne({ _id: user._id }, { history: user.history })
    }

    ctx.succ({
      data: {
        article
      }
    })
  }

  static async getLatestArticle(ctx) {
    const id = ctx.request.params.id || ""
    ctx.verifyParams({
      id: {
        type: 'string', min: 24, max: 24, trim: true, allowEmpty: true, required: false
      }
    }, { id }) //非必填，根据id获取之后的数据

    let articles = []
    const limit = 10
    if (id) {
      articles = await articleModel.find({ _id: { "$lt": id }, publish: true })
        .limit(limit)
        .sort({ _id: -1 })
    } else {
      articles = await articleModel.find({ publish: true })
        .limit(limit)
        .sort({ _id: -1 })
    }

    ctx.succ({
      data: {
        articles
      }
    })
  }

  static async getPublishedArticle(ctx) {
    // TODO: 分页查询
    let uid = ctx.request.query.uid
    ctx.verifyParams({
      uid: {
        type: 'string', min: 24, max: 24, trim: true
      }
    }, { uid })
    console.log('uid:', uid)

    if (!uid) {
      ctx.result({ code: 401, message: "token invalid" })
      return
    }

    let articles = await articleModel.find({
      author_id: uid,
      publish: true
    }).sort({
      publishDate: -1  //按照发布日期倒序
    })

    articles = articles || []

    ctx.succ({
      data: {
        articles
      }
    })
  }

  static async getUnpublishedArticle(ctx) {

    const uid = getuid(ctx)

    let articles = await articleModel.find({
      author_id: uid,
      publish: false
    }).sort({
      createDate: -1  //按照创建日期倒序
    })

    articles = articles || []

    ctx.succ({
      data: {
        articles
      }
    })
  }

  static async getHistory(ctx) {
    const uid = getuid(ctx)
    let { history } = await userModel.findById(uid)

    let idArr = []
    history.forEach(h => {
      idArr.push(h.article_id)
    })

    const _articles = await articleModel.find({ _id: idArr })

    let articles = []
    // 合并阅读时间
    _articles.forEach((v, i) => {
      // 格式化时间
      let readDate = moment(history[i].readDate).utcOffset(8).format('lll')
      articles.push({
        article: v,
        readDate
      })
    })

    ctx.succ({
      data: {
        articles: articles || []
      }
    })
  }

  static async getHot(ctx) {
    const uid = ctx.request.query.uid
    ctx.verifyParams({
      uid: {
        type: 'string', min: 24, max: 24, trim: true
      }
    }, { uid })

    // 查询该用户阅读量高5篇的文章
    let articles = await articleModel.find({ author_id: uid })
      .limit(5)
      .sort({
        readCount: -1
      })

    ctx.succ({
      data: {
        articles
      }
    })
  }

  static async changeArticle(ctx) {
    // 参数校验
    const id = ctx.request.params.id
    ctx.verifyParams({
      id: { type: "string", min: 24, max: 24, required: true }
    }, { id })
    ctx.verifyParams({
      title: { type: 'string', min: 1, max: 50, required: true },
      content: { type: 'string', allowEmpty: true, required: false },
      // not required
      desc: { type: 'string', max: 200, allowEmpty: true, required: false },
      // publish: { type: 'boolean', required: false },
      tags: {
        type: 'array',
        itemType: 'object',
        rule: {
          _id: { type: 'string', min: 24, max: 24, required: true },
          name: { type: 'string', required: true }
        },
        required: false
      },
      category: {
        type: 'object',
        rule: {
          _id: { type: 'string', min: 24, max: 24, required: true },
          name: { type: 'string', required: true }
        },
        required: false
      }
    })
    // 获取参数
    const { title, desc, content,/* publish,*/ tags, category } = ctx.request.body
    const uid = getuid(ctx)

    const article = await articleModel.findOneAndUpdate({
      _id: id,
      author_id: uid
    }, {
      title,
      desc,
      content,
      //publish,
      lastEditDate: Date.now(),
      tags,
      category
    }, {
      new: true
    })

    if (!article) {
      ctx.result({
        code: 404,
        message: '404 not found'
      })
      return
    }

    ctx.succ({ data: true })
  }

  static async setPublish(ctx) {
    const id = ctx.request.params.id
    ctx.verifyParams({
      id: { type: "string", min: 24, max: 24, required: true }
    }, { id })

    const uid = getuid(ctx)

    const publishArticle = await articleModel.findOneAndUpdate({
      _id: id,
      author_id: uid,
    }, {
      publish: true,
      publishDate: Date.now()
    }, {
      new: true
    })

    if (!publishArticle) {
      ctx.result({
        code: 404,
        message: "文章不存在，或该文章不属于该用户"
      })
      return
    }

    ctx.succ({
      data: publishArticle.publish
    })
  }

  static async deleteArticle(ctx) {
    const id = ctx.request.params.id
    ctx.verifyParams({
      id: { type: "string", min: 24, max: 24, required: true }
    }, { id })

    const uid = getuid(ctx)

    const deleteArticle = await articleModel.findOneAndDelete({
      _id: id,
      author_id: uid,
    })

    if (!deleteArticle) {
      ctx.result({
        code: 404,
        message: "文章不存在，或文章不属于该用户"
      })
      return
    }

    ctx.succ({
      data: true
    })
  }

  static async changeTitle(ctx) {
    const id = ctx.request.params.id
    ctx.verifyParams({
      id: { type: 'string', min: 24, max: 24, required: true },
    }, { id })
    ctx.verifyParams({
      title: { type: 'string', min: 1, max: 50, required: true }
    })

    const title = ctx.request.body.title
    const uid = getuid(ctx)

    const article = await articleModel.findOneAndUpdate({
      _id: id,
      author_id: uid
    }, {
      title
    })

    if (!article) {
      ctx.result({
        code: 404,
        message: "文章不存在，或文章不属于该用户"
      })
      return
    }
    // console.log("updateArticle:", updateArticle);

    ctx.succ({
      data: true
    })
  }

  static async changeDesc(ctx) {
    const id = ctx.request.params.id
    ctx.verifyParams({
      id: { type: 'string', min: 24, max: 24, required: true },
    }, { id })
    ctx.verifyParams({
      desc: { type: 'string', max: 200, allowEmpty: true, required: false }
    })
    const desc = ctx.request.body?.desc || ""

    const uid = getuid(ctx)
    const article = await articleModel.findOneAndUpdate({
      _id: id,
      author_id: uid
    }, {
      desc
    })

    if (!article) {
      ctx.result({
        code: 404,
        message: "文章不存在，或文章不属于该用户"
      })
      return
    }

    ctx.succ({
      data: true
    })
  }

  static async changeContent(ctx) {
    const id = ctx.request.params.id
    ctx.verifyParams({
      id: { type: 'string', min: 24, max: 24, required: true },
    }, { id })
    ctx.verifyParams({
      content: { type: 'string', required: true }
    })

    const content = ctx.request.body.content

    const uid = getuid(ctx)
    const article = await articleModel.findOneAndUpdate({
      _id: id,
      author_id: uid
    }, {
      content
    })

    if (!article) {
      ctx.result({
        code: 404,
        message: "文章不存在，或文章不属于该用户"
      })
      return
    }

    ctx.succ({
      data: true
    })
  }

  static async changeTags(ctx) {
    const id = ctx.request.params.id
    ctx.verifyParams({
      id: { type: 'string', min: 24, max: 24, required: true }
    }, { id })
    ctx.verifyParams({
      tags: { type: 'array', required: true } // FIXME: 要判断数组元素的格式类型(使用 itemType参数)
    })

    const tags = ctx.request.body.tags

    const uid = getuid(ctx)
    const article = await articleModel.findOneAndUpdate({
      _id: id,
      author_id: uid
    }, {
      tags
    })

    if (!article) {
      ctx.result({
        code: 404,
        message: "文章不存在，或文章不属于该用户"
      })
      return
    }

    ctx.succ({
      data: true
    })
  }

  static async changeCategory(ctx) {
    const id = ctx.request.params.id
    ctx.verifyParams({
      id: { type: 'string', min: 24, max: 24, required: true }
    }, { id })
    ctx.verifyParams({
      category_id: { type: 'string', min: 24, max: 24, required: true }
    })

    // get category
    const category_id = ctx.request.body.category_id
    const category = await categoryModel.findById(category_id)

    if (!category) {
      ctx.result({
        code: 404,
        message: "分类不存在"
      })
      return
    }

    // update category
    const uid = getuid(ctx)
    const article = await articleModel.findOneAndUpdate({
      _id: id,
      author_id: uid
    }, {
      category
    })

    if (!article) {
      ctx.result({
        code: 404,
        message: "文章不存在，或文章不属于该用户"
      })
      return
    }

    ctx.succ({
      data: true
    })
  }
}

module.exports = {
  ArticleController
}